package pri.zxx.webdemo.utils.poi;

import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pri.zxx.learndemo.localUtils.LocalDateUtil;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;

/**
 * @ClassName ExportBaseService
 * @description todo
 * @Author nemoy
 * @Version 1.0
 */
public class ExportBaseService<T> {
    public static Logger log = LoggerFactory.getLogger(ExportBaseService.class);
    private ExportHeader header;
    private String sheetName;
    //写入xls
//    private HSSFWorkbook workbook = new HSSFWorkbook();
//
    SXSSFWorkbook workbook = new SXSSFWorkbook(); //xlsx

    public ExportBaseService(String sheetName) {
        this.sheetName = sheetName;
    }

    private void setHeader(SXSSFSheet sheet) {
        //header 样式
        CellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        Font font = workbook.createFont();
        font.setBold(true);
        font.setFontHeightInPoints((short) 14);
        font.setFontName("微软雅黑");
        cellStyle.setFont(font);

        int i = 0;
        for (ExportRow r : header.getList()) {
            SXSSFRow row = sheet.createRow(i);
            for (ExportCell c : r.getList()) {
                SXSSFCell cell = row.createCell(c.getStart());
                cell.setCellValue(c.getValue());
                cell.setCellStyle(cellStyle);
                if (c.getEnd() - c.getStart() > 0) {
                    CellRangeAddress region = new CellRangeAddress(i, i, c.getStart(), c.getEnd());
                    sheet.addMergedRegion(region);
                }
            }
            i++;
        }
    }

    public ExportBaseService<T> titleAndSecond(String secondCellValue, Map<String, String> nameAndValues) {
        Collection<String> titles = nameAndValues.values();
        //first row
        header = new ExportHeader(2);
        ExportCell secondCells = new ExportCell(LocalDateUtil.formatter(LocalDateTime.now()) + "--" + secondCellValue, 0, titles.size() - 1);
        ExportRow secondRow = new ExportRow();
        secondRow.add(secondCells);
        header.add(secondRow);
        //second row
        ExportRow rowTwo = new ExportRow();
        Integer i = 0;
        for (String str : titles) {
            ExportCell cc = new ExportCell(str, i, i++);
            rowTwo.add(cc);
        }
        header.add(rowTwo);
        return this;
    }


    public ExportBaseService<T> contents(List<T> data, Map<String, String> namesAndValues, BiFunction<String, T, String> biFunction) {
        SXSSFSheet sheet = workbook.createSheet(sheetName);
        workbook.setCompressTempFiles(true);
        setHeader(sheet);
        setListData(sheet, data, namesAndValues, biFunction);
//        IntStream.iterate(0, operand -> operand + 1)
//                .limit(namesAndValues.size())
//                .forEach(value -> sheet.autoSizeColumn(value, true));
        return this;
    }

    private void setListData(SXSSFSheet sheet, List<T> data, Map<String, String> nameAndValues, BiFunction<String, T, String> biFunction) {
        try {
            int i = 2;
            if (nameAndValues == null || nameAndValues.size() == 0) {
                throw new RuntimeException("数据名称为空");
            }
            if (data == null || data.size() == 0) {
                return;
            }

            Class<? extends T> aClass = (Class<? extends T>) data.get(0).getClass();
            String[] names = nameAndValues.keySet().toArray(new String[0]);
            int len = names.length;
            CellStyle cellStyle = workbook.createCellStyle();
            Font font = workbook.createFont();
            font.setFontHeightInPoints((short) 12);
//            cellStyle.setAlignment(HorizontalAlignment.LEFT);
            cellStyle.setFont(font);
            SXSSFRow row;
            SXSSFCell cell;
            String fieldValue;
            for (T item : data) {
                row = sheet.createRow(i++);
                for (int j = 0; j < len; j++) {
                    cell = row.createCell(j);
                    //先用自定义方法获取数据
                    fieldValue = biFunction.apply(names[j], item);
                    //利用反射从实体中获取数据
                    if (fieldValue == null) {
                        Object obj = aClass.getMethod("get" + names[j]).invoke(item);
                        fieldValue = (obj == null ? "" : obj.toString());
                    }
                    cell.setCellValue(fieldValue);
                    cell.setCellStyle(cellStyle);
                }
            }
        } catch (Exception e) {
            log.error("set content exception", e);
        }
    }

    public SXSSFWorkbook getWorkbook() {
        return workbook;
    }

    static class ExportHeader {
        private List<ExportRow> list;

        public ExportHeader(Integer c) {
            if (c > 0) {
                this.list = new ArrayList<>(c);
            } else {
                System.out.println("export xls header count not valid");
            }
        }

        public List<ExportRow> getList() {
            return list;
        }

        public void setList(List<ExportRow> list) {
            this.list = list;
        }

        public void add(ExportRow r) {
            list.add(r);
        }
    }

    static class ExportCell {

        private String value;

        private Integer start;

        private Integer end;

        public ExportCell(String value, Integer start, Integer end) {
            this.value = value;
            this.start = start;
            this.end = end;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }

        public Integer getStart() {
            return start;
        }

        public void setStart(Integer start) {
            this.start = start;
        }

        public Integer getEnd() {
            return end;
        }

        public void setEnd(Integer end) {
            this.end = end;
        }
    }

    static class ExportRow {
        private List<ExportCell> list = new ArrayList<>();

        public List<ExportCell> getList() {
            return list;
        }

        public void setList(List<ExportCell> list) {
            this.list = list;
        }

        public void add(ExportCell c) {
            list.add(c);
        }
    }

}

